cesium 重心插值生成线框

为了在你的自定义**CityPrimitive**中添加重心坐标,你需要修改你的几何体数据,为每个顶点增加这些坐标。重心坐标是一个在三角形顶点上为**[1, 0, 0]**,**[0, 1, 0]**,**[0, 0, 1]**,并在内部插值的属性。这样,三角形的每个边上的坐标都会接近零,并且可以在片段着色器中用来判断一个片段是否接近边缘。

首先,你需要为你的几何体的每个三角形的顶点生成这些坐标。在 Cesium 中,可以在你创建顶点属性的时候添加这些坐标。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 生成重心坐标属性
function generateBarycentricCoordinates(geometry) {
const numberOfVertices = Cesium.Geometry.computeNumberOfVertices(geometry);
const barycentricCoordinates = new Float32Array(numberOfVertices * 3);

for (let i = 0, len = numberOfVertices / 3; i < len; ++i) {
barycentricCoordinates[i * 9 + 0] = 1; // 第一个顶点
barycentricCoordinates[i * 9 + 1] = 0;
barycentricCoordinates[i * 9 + 2] = 0;

barycentricCoordinates[i * 9 + 3] = 0; // 第二个顶点
barycentricCoordinates[i * 9 + 4] = 1;
barycentricCoordinates[i * 9 + 5] = 0;

barycentricCoordinates[i * 9 + 6] = 0; // 第三个顶点
barycentricCoordinates[i * 9 + 7] = 0;
barycentricCoordinates[i * 9 + 8] = 1;
}

return new Cesium.GeometryAttribute({
componentDatatype: Cesium.ComponentDatatype.FLOAT,
componentsPerAttribute: 3,
values: barycentricCoordinates,
});
}

// 在你的几何体中添加重心坐标属性
this.geometry.attributes.barycentric = generateBarycentricCoordinates(this.geometry);

接着,在你的createCommand函数中,你需要确保这个新属性被传递到着色器中,并且绑定到一个顶点着色器输入:

1
2
3
4
5
6
7
javascriptCopy code
const attributeLocations = {
position: 0,
normal: 1,
st: 2,
barycentric: 3 // 添加新的属性位置
};

然后,在你的顶点着色器中,你需要接收并传递这个属性到片段着色器:

1
2
3
4
5
6
7
8
9
10
11
glslCopy code
// 顶点着色器
// ...
in vec3 barycentric;
out vec3 v_barycentric;

void main() {
// ...
v_barycentric = barycentric;
// ...
}

最后,在你的片段着色器中,你需要使用这个v_barycentric来确定是否绘制线框:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
glslCopy code
// 片段着色器
// ...
in vec3 v_barycentric;

void main() {
// 根据重心坐标确定是否绘制线框
float lineWidth = 0.01; // 设置线宽
if (min(min(v_barycentric.x, v_barycentric.y), v_barycentric.z) < lineWidth) {
// 接近边缘,绘制线框
out_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
// 在三角形内部,根据需要设置颜色
discard; // 或者适当设置颜色
}
}

请记住,这些修改都需要适应你当前的代码和 Cesium 的使用方式。具体细节可能需要进一步调整以确保与你的应用程序兼容。

在 3D 图形学中,重心坐标(Barycentric coordinates)用于表示在三角形内部的点相对于三角形顶点的位置。一个点的重心坐标是三个数(通常记作�,�,�u,v,w),它们的和为 1,每个数对应于点在三角形一个顶点上的“权重”。在图形 API 中,重心坐标通常用于插值(如纹理坐标、颜色等)。

当给每个三角形的顶点赋予不同的重心坐标:

  • 第一个顶点:(1,0,0)(1,0,0)
  • 第二个顶点:(0,1,0)(0,1,0)
  • 第三个顶点:(0,0,1)(0,0,1)

在三角形的边上,至少有一个重心坐标将接近 0(因为边上的点只有两个顶点的“权重”)。在三角形内部,每个重心坐标都将大于 0。

所以,当你看到这样的代码:

1
2
3
4
glslCopy code
if (min(min(v_barycentric.x, v_barycentric.y), v_barycentric.z) < lineWidth) {
// ...
}

这段代码的意思是:如果在三个重心坐标中有任何一个接近 0(小于lineWidth),那么当前片段(Pixel)就处于三角形的边上或接近边缘。在这种情况下,如果你想渲染线框,你会在这些接近边缘的片段上应用一种颜色(如黑色),从而绘制出线框的效果。

而关于您的第一个问题,确实,这是一个顶点对应一个重心坐标,这三个顶点的重心坐标((1,0,0)(1,0,0), (0,1,0)(0,1,0), (0,0,1)(0,0,1))被分配给了三角形的三个顶点,这样可以在三角形内部以及边缘上插值这些坐标。当你在顶点着色器中将这些坐标传递到片段着色器,然后在片段着色器中使用这些坐标来检测边缘,你就能实现线框渲染的效果。

作者

wangyawei

发布于

2025-03-21

更新于

2025-03-21

许可协议